package cn.piesat.util;

import org.springframework.stereotype.Component;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.io.File;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
import java.util.Random;
import java.util.UUID;

@Component
public class DESEncryptUtil {
	
	private String IV;
	
	public DESEncryptUtil() {
		File file = new File(System.getProperty("user.dir")+"/decrypt.properties");
		if(!file.exists()) {
			try {
				file.createNewFile();
				PropertiesFileUtil properties = new PropertiesFileUtil(file);
				OrderedPropertiesUtils orderedProperties = properties.readPropertiesFile();
				this.IV = this.getRandomString(8);
				orderedProperties.setProperty("decrypt.key", this.IV);
				properties.writePropertiesFile(orderedProperties);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}else {
			PropertiesFileUtil properties = new PropertiesFileUtil(file);
			OrderedPropertiesUtils orderedProperties = properties.readPropertiesFile();
			this.IV = orderedProperties.getProperty("decrypt.key");
		}
		
	}
	
	/**
	 * DESCBC加密
	 * @param src 数据源
	 * @param key 密钥，长度必须是8的倍数
	 * @return 返回加密后的数据
	 * @throws Exception
	 */
	public String encryptDESCBC(final String src, final String key) throws Exception {

        // --生成key,同时制定是des还是DESede,两者的key长度要求不同
        final DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
        final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        final SecretKey secretKey = keyFactory.generateSecret(desKeySpec);

        // --加密向量
        final IvParameterSpec iv = new IvParameterSpec(IV.getBytes("UTF-8"));

        // --通过Chipher执行加密得到的是一个byte的数组,Cipher.getInstance("DES")就是采用ECB模式,cipher.init(Cipher.ENCRYPT_MODE,
        // secretKey)就可以了.
        final Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
        final byte[] b = cipher.doFinal(src.getBytes("UTF-8"));

        // --通过base64,将加密数组转换成字符串
        final Encoder endoder = Base64.getMimeEncoder();
        return endoder.encodeToString(b);
    }

	/**
	 * DESCBC解密
	 * @param src 数据源
	 * @param key 密钥，长度必须是8的倍数
	 * @return 返回解密后的原始数据
	 * @throws Exception
	 */
    public String decryptDESCBC(final String src, final String key) throws Exception {
        // --通过base64,将字符串转成byte数组
    	final Decoder decoder= Base64.getMimeDecoder();
        final byte[] bytesrc = decoder.decode(src);

        // --解密的key
        final DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
        final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        final SecretKey secretKey = keyFactory.generateSecret(desKeySpec);

        // --向量
        final IvParameterSpec iv = new IvParameterSpec(IV.getBytes("UTF-8"));

        // --Chipher对象解密Cipher.getInstance("DES")就是采用ECB模式,cipher.init(Cipher.DECRYPT_MODE,
        // secretKey)就可以了.
        final Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
        final byte[] retByte = cipher.doFinal(bytesrc);

        return new String(retByte);

    }

    // 3DESECB加密,key必须是长度大于等于 3*8 = 24 位哈
    public String encryptThreeDESECB(final String src, final String key) throws Exception {
        final DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));
        final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
        final SecretKey securekey = keyFactory.generateSecret(dks);

        final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, securekey);
        final byte[] b = cipher.doFinal(src.getBytes());

        final Encoder endoder = Base64.getMimeEncoder();
        return endoder.encodeToString(b).replaceAll("\r", "").replaceAll("\n", "");

    }

    // 3DESECB解密,key必须是长度大于等于 3*8 = 24 位哈
    public String decryptThreeDESECB(final String src, final String key) throws Exception {
        // --通过base64,将字符串转成byte数组
        final Decoder decoder= Base64.getMimeDecoder();
        final byte[] bytesrc = decoder.decode(src);
        
        // --解密的key
        final DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));
        final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
        final SecretKey securekey = keyFactory.generateSecret(dks);

        // --Chipher对象解密
        final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, securekey);
        final byte[] retByte = cipher.doFinal(bytesrc);

        return new String(retByte);
    }
    
    /**
     * 获取随机位数字符串
     * @param length 获取长度
     * @return
     */
    public static String getRandomString(int length) {
		String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
		SecureRandom random = new SecureRandom();
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < length; i++) {
			int number = random.nextInt(62);
			sb.append(str.charAt(number));
		}
		return sb.toString();
	}
	
    /**
     * 获取15位长度uuid 哈希数字
     * @return
     */
	public String getBy15UUIdNumber() {
        int first = new Random().nextInt(9) + 1;
        int hashCodeV = UUID.randomUUID().toString().hashCode();
        if (hashCodeV < 0) {//有可能是负数
            hashCodeV = -hashCodeV;
        }
        // 0 代表前面补充0
        // 14 代表长度为14
        // d 代表参数为正数型
        return first + String.format("%014d", hashCodeV);
    }
	
	public static void main(String[] args) {
		DESEncryptUtil desEncryptUtil = new DESEncryptUtil();
		String s = "lkBWEPAR9gPP11XakOXgCw==";
		System.out.println(s.length());
		try {
			String decryptThreeDESECB = desEncryptUtil.encryptThreeDESECB("1234567890", "lkBWEPAR9gPP11XakOXgCw==");
			System.out.println(decryptThreeDESECB);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
